home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D GFX
/
3D GFX.iso
/
amiutils
/
e_h
/
getilbm
/
getilbm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-30
|
32KB
|
882 lines
//===========================================================================
// GETILBM.C -- for AmigaDOS 2.0/3.0 (and maybe 1.3 with iffparse.library)
// Rev: 30 September 1994, Alex Matulich matulich_alex@SEAA.NAVSEA.NAVY.MIL
//
// For SAS C/C++ 6.xx. Compile with IGNORE=51 to disable warnings for
// C++ comments (I got addicted to those C++ comments...)
//
// This module is for loading IFF ILBM pictures. The *only* functions you
// need to call are loadilbmScreen() and freeilbmScreen(), or if you are
// just loading into bitmaps, call loadilbmBitMap() and freeBitMap().
//
// The iffparse.library must be opened prior to calling these routines.
// SAS C 6.xx does this automatically for you.
//
// This module was adapted from the confusing plethora of functions in the
// Amiga Developer's package for AmigaDOS 3.1. All adaptations and excerpts
// are indicated in the comments.
//===========================================================================
//---------------------------------------------------------------------------
// To make the demo ILBM file reader, compile with only the symbol DEMO
// defined. Example: sc optimize optsize def=DEMO link getilbm.c
//
// You might have your own versions of getBitMap() and freeBitMap() external
// to this module (I do, for example, in my video buffering module). If so,
// then make sure the following two #defines are commented out. If you wish
// to use the getBitMap() and freeBitMap() functions contained in this
// module, then uncomment the following two #defines.
// #define USE_GETBM // comment out if you already have a getBitMap()
// #define USE_FREEBM // comment out if you already have a freeBitMap()
// These functions, if external, should be compatible with the prototypes
// in getilbm_proto.h.
//
// Defining TIMECHECK enables calls to a user-supplied external function
// check_for_switch() while the IFF file is loading. The purpose of this
// function is to allow the program to do time-critical things while a
// large ILBM file is loading. Sort of a pseudo-multitasking technique.
// #define TIMECHECK // only if you need a check_for_switch() function
// Often it is more useful to simply load an IFF file into a bitmap, rather
// than create a whole screen for it. If you want to do just this, and you
// never need to load an IFF file into a screen, then uncomment this line:
// #define NOILBMSCREEN // only compile loadilbmBitMap() and associates
// This will cause the functions loadilbmScreen() and associated functions
// and declarations to be skipped during compililation.
//
// Conversely, if you don't need loadilbmBitMap(), but only loadilbmScreen(),
// then uncomment this line:
//
// #define ILBMSCREENONLY // only compile loadilbmScreen() and associates
//
// The existence of getBitMap() and freeBitMap() are still controlled by
// USE_GETBM and USE_FREEBM.
// Do not define both NOILBMSCREEN and ILBMSCREENONLY at the same time.
// Do not define either of them if you need *both* loadilbmScreen() and
// loadilbmBitMap().
//---------------------------------------------------------------------------
#ifdef NOTIMECHECK // for compatibility with previous versions
#undef TIMECHECK
#endif
#ifdef DEMO // re-set definitions if compiling the demo
#ifdef USE_GETBM
#undef USE_GETBM // demo doesn't need getBitMap()
#endif
#ifdef USE_FREEBM
#undef USE_FREEBM // demo doesn't need freeBitMap()
#endif
#ifdef TIMECHECK
#undef TIMECHECK // demo doesn't need check_for_switch()
#endif
#ifdef NOILBMSCREEN
#undef NOILBMSCREEN // demo doesn't need loadilbmBitmap()
#endif
#ifndef ILBMSCREENONLY
#define ILBMSCREENONLY // demo DOES need loadilbmScreen()
#endif
#endif
#include <exec/memory.h>
#include <exec/libraries.h>
#include <graphics/gfx.h>
#include <libraries/dos.h>
#include <libraries/iffparse.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#include <proto/iffparse.h>
#ifndef NOILBMSCREEN
#define USE_BUILTIN_MATH 1 // to use built-in min() and max() in string.h
#include <string.h>
#include <graphics/display.h>
#include <intuition/intuition.h>
#include <proto/intuition.h>
#endif // !NOILBMSCREEN
#include <stdlib.h>
#include "getilbm_proto.h" // prototypes for user-callable functions
extern struct Library *IFFParseBase;
// definitions from iffp/iff.h
#define ChunkMoreBytes(cn) (cn->cn_Size - cn->cn_Scan)
struct Chunk {
struct Chunk *ch_Next;
long ch_Type, ch_ID, ch_Size;
void *ch_Data;
};
// definitions from iffp/ilbm.h
#define ID_ILBM MAKE_ID('I','L','B','M')
#define ID_BMHD MAKE_ID('B','M','H','D')
#define ID_CMAP MAKE_ID('C','M','A','P')
#define ID_BODY MAKE_ID('B','O','D','Y')
#define ID_CAMG MAKE_ID('C','A','M','G')
// sizeof(a 3-byte structure) returns 16 due to word alignment, so we use:
#define sizeofColorRegister 3
#define MAXAMDEPTH 8 // used for OS<V37, screen.c maxdisplaydepth(ID)
#define MAXAMCOLORREG 32 // should use ViewPort->ColorMap.Count instead
#define RowBytes(w) ((((w) + 15) >> 4) << 1)
#define RowBits(w) ((((w) + 15) >> 4) << 4)
#define mskNone 0 // masking techniques
#define mskHasMask 1
#define cmpNone 0 // compression techniques
#define cmpByteRun1 1
typedef struct {
UWORD w, h; // raster width and height
WORD x, y; // pixel position for this image
UBYTE nPlanes, masking, // # source bitplanes, masking (?)
compression, flags; // compression, Commodore-defined flags
UWORD transparentColor; // transparent color number (sort of)
UBYTE xAspect, yAspect; // pixel aspect ratio width/height
WORD pageWidth, pageHeight; // source page size in pixels
} BitMapHeader;
typedef struct { UBYTE red, green, blue; } ColorRegister;
typedef struct { ULONG ViewModes; } CamgChunk;
#define BMHDB_CMAPOK 7
#define BMHDF_CMAPOK (1 << BMHDB_CMAPOK)
// from iffp/packer.h
#define MaxPackedSize(rowsize) ((rowsize)+(((rowsize)+127)>>7))
//---------------------------------------------------------------------------
// Skip following five declarations if you don't need loadilbmScreen().
#ifndef NOILBMSCREEN
static UWORD __far ins_pens[] = { 0xffff }; // minimal pen definitions
long li_errcode; // error code returned by OpenScreen()
// You will want to expand the following tag list if you decide to
// substitute OpenScreenTagList() for OpenScreen() in loadilbmScreen().
// OpenScreen() works with all video modes, and is used here for
// compatibility with AmigaDOS 1.3, just in case such an OS happens to
// have a compatible iffparse.library.
static struct TagItem __far ins_ext[] = {
SA_DisplayID, 0L, // tag needed for display mode
SA_DClip, 0L, // needed for screen centering
SA_AutoScroll, TRUE, // not really needed, but who cares?
SA_Pens, (ULONG)ins_pens, // minimal tags needed for 2.0
SA_ErrorCode, (ULONG)&li_errcode, // examine li_errcode for error codes
TAG_DONE
};
// Instead of opening a screen with functions specific to AmigaDOS 2.0,
// we define an ExtNewScreen structure for use with OpenScreen() to
// maintain compatibility with earlier OS versions. The ins_ext[] taglist
// above provides the enhancements necessary for OS 2.0 or greater.
static struct ExtNewScreen __far ins = {
0, 0, ~0, ~0, // left, top, width & height
2, 0, 1, // depth, DetailPen, BlockPen
0, // ViewModes
CUSTOMSCREEN | SCREENQUIET | SCREENBEHIND | NS_EXTENDED,
NULL, // font
NULL, NULL, NULL, // title, gadgets, bitmap
ins_ext // tag extensions
};
static struct NewWindow __far inw = {
0, 0, ~0, ~0, // left, top, width, height
0, 1, // DetailPen, BlockPen
IDCMP_RAWKEY | IDCMP_VANILLAKEY, // IDCMP flags (whatever you like)
SIMPLE_REFRESH | BORDERLESS | BACKDROP | NOCAREREFRESH,
NULL, // pointer to 1st user gadget
NULL, // pointer to user checkmark
NULL, // title
NULL, // pointer to window screen
NULL, // no superbitmap
100,100,100,100, // width & height, min & max
CUSTOMSCREEN
};
#endif // !NOILBMSCREEN
//---------------------------------------------------------------------------
// internal prototypes
struct IFFHandle *getilbminfo(char *, USHORT *, USHORT *,
USHORT *, WORD **, USHORT *, unsigned long *, BitMapHeader **);
void freeIFFHandle(struct IFFHandle *iff);
int loadbody(struct IFFHandle *, struct BitMap *, BitMapHeader *);
int loadbody2(struct IFFHandle *, struct BitMap *, BYTE *,
BitMapHeader *, BYTE *, ULONG);
BOOL unpackrow(BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0);
#ifdef DEMO
//===========================================================================
// DEMO main() FUNCTION
// For demonstrating loadilbmScreen().
//===========================================================================
#include <stdio.h>
int main(int argc, char *argv[])
{
struct Screen *s; // pointer to the screen that will be shown
struct Message *msg; // this is for trapping keystrokes
int i = 0, err = 0;
if (argc < 2) {
fputs("ILBM Viewer\nNeeds filenames as commandline arguments.\n", stderr);
return err;
}
fputs("Press any key to finish viewing an image.\n\n", stderr);
while (++i < argc) { // go thru all commandline arguments
fputs("loading ", stderr); // display the filename being loaded
fputs(argv[i], stderr);
fflush(stderr); // make sure the name is displayed
if (s = loadilbmScreen(argv[i])) { // load ILBM file
ScreenToFront(s); // show it if loaded
ActivateWindow(s->FirstWindow); // setup for keypress
Wait(1L<<s->FirstWindow->UserPort->mp_SigBit); // wait for key
while (msg = GetMsg(s->FirstWindow->UserPort)) // clear msg buffer
ReplyMsg(msg);
freeilbmScreen(s, NULL); // close the screen
fputs("\n", stderr);
} // go on to next file
else { // or report an error
fputs("... bad, incompatible, or nonexistent.\n", stderr);
++err;
}
}
return err;
}
//===========================================================================
#endif // end of DEMO
#ifndef NOILBMSCREEN // ingore next 3 functions if NOILBMSCREEN is defined
//===========================================================================
// CLIPIT -- called by loadilbmScreen() below
// Adapted with minor changes from modules/screen.c
//===========================================================================
static void clipit(short wide, short high,
struct Rectangle *spos, struct Rectangle *dclip,
struct Rectangle *txto, struct Rectangle *stdo,
struct Rectangle *maxo, struct Rectangle *uclip, BOOL NoCenter)
{
struct Rectangle *besto;
short minx, maxx, miny, maxy,
txtw, txth, stdw, stdh, bestw, besth;
// get txt, std, and max widths and heights
txtw = txto->MaxX - txto->MinX + 1;
txth = txto->MaxY - txto->MinY + 1;
stdw = stdo->MaxX - stdo->MinX + 1;
stdh = stdo->MaxY - stdo->MinY + 1;
if (wide <= txtw && high <= txth) {
besto = txto;
bestw = txtw;
besth = txth;
}
else {
besto = stdo;
bestw = stdw;
besth = stdh;
}
if (uclip) {
*dclip = *uclip;
spos->MinX = uclip->MinX;
spos->MinY = uclip->MinY;
}
else {
spos->MinX = minx = besto->MinX - ((wide - bestw) >> 1);
maxx = wide + minx - 1;
if (maxx > maxo->MaxX) maxx = maxo->MaxX;
if (minx < maxo->MinX) {
minx = maxo->MinX;
if (NoCenter) spos->MinX = minx;
}
miny = besto->MinY - ((high - besth) >> 1);
spos->MinY = miny = min(miny, txto->MinY);
maxy = high + miny - 1;
if (maxy > maxo->MaxY) maxy = maxo->MaxY;
if (miny < maxo->MinY) {
miny = maxo->MinY;
if (NoCenter) spos->MinY = miny;
}
dclip->MinX = minx;
dclip->MinY = miny;
dclip->MaxX = spos->MaxX = maxx;
dclip->MaxY = spos->MaxY = maxy;
}
}
//===========================================================================
// LOADILBMSCREEN
// Loads an IFF ILBM file into a bitmap and creates a custom screen to
// display it, returning a pointer to the screen. The screen is created
// behind others; use ScreenToFront() to show, and freeilbmScreen() to
// deallocate the screen. If IFF ILBM file failed to load, NULL is returned
// and the global long li_errcode is set as defined in <intuition/screens.h>:
// (0): IFF ILBM file loaded, screen created successfully
// (1) OSERR_NOMONITOR: Monitor specification unavailable
// (2) OSERR_NOCHIPS: You need newer custom chips
// (3) OSERR_NOMEM: Insufficient normal RAM
// (4) OSERR_NOCHIPMEM: Insufficient chip RAM
// (5) OSERR_PUBNOTUNIQUE: Public screen name already used
// (6) OSERR_UNKNOWNMODE: Unrecognized screen mode
// (7) OSERR_TOODEEP: Too many bitplanes in requested screen
// (8) OSERR_ATTACHFAIL: Failed to attach screens
// (9) OSERR_NOTAVAILABLE: Mode unavailable for some other reason
// other: Unknown error
//===========================================================================
struct Screen *loadilbmScreen(char *filename)
{
BitMapHeader *bmhd;
struct Screen *iscr = NULL;
struct Window *iwnd = NULL;
USHORT wide, high, deep, colors = MAXAMCOLORREG, err = 0;
WORD *colortable = NULL;
unsigned long mode;
struct Rectangle spos, dclip, txto, stdo, maxo;
struct IFFHandle *iff = getilbminfo(filename, &wide, &high, &deep,
&colortable, &colors, &mode, &bmhd);
if (!iff) return NULL;
li_errcode = 0;
// The following if() block was adapted from modules/screen.c
if ( ((struct Library *)GfxBase)->lib_Version >= 36) {
if (li_errcode = ModeNotAvailable(mode))
goto lis_done;
else {
QueryOverscan(mode, &txto, OSCAN_TEXT);
QueryOverscan(mode, &stdo, OSCAN_STANDARD);
QueryOverscan(mode, &maxo, OSCAN_MAX);
}
clipit(wide, high, &spos, &dclip, &txto, &stdo, &maxo, NULL, FALSE);
}
else spos.MinX = spos.MinY = 0;
ins.LeftEdge = spos.MinX; // these should all go into a taglist if
ins.TopEdge = spos.MinY; // you decide to substitute
ins.Width = inw.Width = wide; // OpenScreenTagList() for OpenScreen().
ins.Height = inw.Height = high;
ins.Depth = deep;
ins.ViewModes = 0xffff & (ins.Extension[0].ti_Data = mode);
ins.Extension[1].ti_Data = (ULONG)&dclip;
if (iscr = OpenScreen(&ins)) { // You might substitute OpenScreenTagList()
inw.Width = wide;
inw.Height = high;
inw.Screen = iscr;
if (!(iwnd = OpenWindow(&inw))) {
err = 1;
goto lis_done;
}
if (err = loadbody(iff, &iscr->BitMap, bmhd)) goto lis_done;
if (colortable)
if (((struct Library *)GfxBase)->lib_Version < 39)
LoadRGB4(&iscr->ViewPort, (UWORD *)colortable, colors);
else
LoadRGB32(&iscr->ViewPort, (ULONG *)colortable);
}
// The error code for extern long li_errcode may be checked here.
// See getilbm_proto.h for possible values.
lis_done:
if (err) {
if (iwnd) CloseWindow(iwnd);
if (iscr) CloseScreen(iscr);
iscr = NULL;
}
if (colortable) free(colortable);
freeIFFHandle(iff); // IFF handle must be freed before exiting
return iscr;
}
//===========================================================================
// FREEILBMSCREEN
// Free a screen created by loadilbmScreen(). If you saved the Window's
// *original* UserPort because you needed to share another one, pass it here,
// or just pass NULL if the Window still has its original UserPort.
// This function is not needed if you don't need loadilbmScreen().
//===========================================================================
void freeilbmScreen(struct Screen *iscr, struct MsgPort *userport)
{
struct Window *fw = iscr->FirstWindow;
if (fw) {
struct IntuiMessage *msg;
if (userport) fw->UserPort = userport;
while (msg = (struct IntuiMessage *)GetMsg(fw->UserPort))
ReplyMsg((struct Message *)msg);
CloseWindow(fw);
}
CloseScreen(iscr);
}
#endif // !NOILBMSCREEN
#ifndef ILBMSCREENONLY // ignore next function if ILBMSCREENONLY defined
//===========================================================================
// LOADILBMBITMAP
// Allocate a bitmap and load an ILBM file into it. The size of the bitmap
// allocated is returned in wide, high, and deep, and function returns a
// pointer to the bitmap, or NULL in the case of an error. wide, high, and
// deep should all be pointers to unsigned short variables. These variables
// will be set to the dimensions of the BitMap when the function returns.
// Remember to free the bitmap with freeBitMap() when you're done with it.
//===========================================================================
struct BitMap
*loadilbmBitMap(char *filename, USHORT *wide, USHORT *high, USHORT *deep)
{
BitMapHeader *bmhd;
struct BitMap *bitmap;
struct IFFHandle *iff = getilbminfo(filename, wide, high, deep,
NULL, NULL, NULL, &bmhd);
if (!iff) return NULL;
// allocate a bitmap according to the data in the bitmap header
// and load the ILBM file into the bitmap
if (bitmap = getBitMap(*wide, *high, *deep, 1))
if (loadbody(iff, bitmap, bmhd)) {
freeBitMap(bitmap); // load was unsuccessfull
bitmap = NULL;
}
freeIFFHandle(iff); // IFF handle must be freed before exiting
return bitmap;
}
#endif // !ILBMSCREENONLY
//===========================================================================
// GETILBMINFO -- called by loadilbmScreen() and loadilbmBitMap()
// Return an IFF handle for use with loadbody() to load an ILBM body into
// a bitmap, and set all the appropriate parameters to their correct values.
// ALL arguments are pointers. Only colortable, colors, and mode may be
// passed as NULL. Colormap entries are returned in *colortable (which this
// function allocates), and number of colors in colors. If <V39, colortable
// is stored as the old 4-bit-per-gun style, and must be appropriately cast.
// If colors is returned as 0xffff, then a colormap was not found. If you
// don't want color info, pass NULL for colors and colortable. Likewise for
// the parameter video mode. bmhd must point to an uninitialized
// BitMapHeader, which will have its contents initialized inside this
// function. The IFFHandle returned must be freed later by the calling
// function using freeIFFHandle().
// Upon exit, the parser will be stopped at the beginning of the BODY chunk
// of the ILBM file, so that loadbody() can work properly.
//===========================================================================
struct IFFHandle
*getilbminfo(char *filename, USHORT *wide, USHORT *high, USHORT *deep,
WORD **colortable, USHORT *colors, unsigned long *mode, BitMapHeader **bmhd)
{
struct StoredProperty *sp;
struct IFFHandle *iff;
if (!IFFParseBase) return NULL;
// open things
if (!(iff = AllocIFF())) return NULL;
if (!(iff->iff_Stream = Open(filename, MODE_OLDFILE))) goto iffdone;
InitIFFasDOS(iff);
if (OpenIFF(iff, IFFF_READ)) goto iffdone;
#ifdef TIMECHECK
check_for_switch();
#endif
// set up the parser and parse the file
if (PropChunk(iff, ID_ILBM, ID_BMHD)) goto iffdone;
PropChunk(iff, ID_ILBM, ID_CMAP);
PropChunk(iff, ID_ILBM, ID_CAMG);
if (StopChunk(iff, ID_ILBM, ID_BODY)) goto iffdone; // stop at start of body
if (ParseIFF(iff, IFFPARSE_SCAN)) goto iffdone;
#ifdef TIMECHECK
check_for_switch();
#endif
// extract header and determine dimensions
// From modules/getbitmap.c
if (!(sp = FindProp(iff, ID_ILBM, ID_BMHD))) goto iffdone;
*bmhd = (BitMapHeader *)sp->sp_Data;
*wide = RowBits((*bmhd)->w);
*high = (*bmhd)->h;
*deep = (*bmhd)->nPlanes;
#ifndef NOILBMSCREEN // don't need colormap or mode info for bitmaps
// pull out colormap data that was read in if colors & coloratble was passed
// Adapted from loadcmap() in modules/ilbmr.c
if (colors) { // get colormap information
if (sp = FindProp(iff, ID_ILBM, ID_CMAP)) {
register UBYTE *rgb = sp->sp_Data;
long r, g, b;
ULONG ncheck;
USHORT i, ncolors = *colors = sp->sp_Size / sizeofColorRegister;
if ((ncheck = 1 << (*bmhd)->nPlanes) > ncolors) ncheck = ncolors;
if (((struct Library *)GfxBase)->lib_Version >= 39) {
// for a moment we visit an adaptation of alloccolortable()
// in modules/ilbmr.c ....
Color32 *ct;
UWORD AllShifted = TRUE;
USHORT nc = max(ncolors, 32);
if (!(*colortable = (WORD *)calloc( (nc*sizeof(Color32)) + (4*sizeof(WORD)), 1)))
goto errctab;
ct = (Color32 *)(*colortable + 2);
**colortable = nc;
// now back to loadcmap() in modules/ilbmr.c ....
i = 0;
while (ncheck--) {
ct[i].r = r = *rgb++;
ct[i].g = g = *rgb++;
ct[i++].b = b = *rgb++;
if ((r & 0x0f) || (g & 0x0f) || (b & 0x0f)) AllShifted = FALSE;
}
if (AllShifted && ((*bmhd)->flags & BMHDF_CMAPOK)) // shift if 4-bit
for (i = 0; i < ncolors; i++) {
ct[i].r |= (ct[i].r >> 4);
ct[i].g |= (ct[i].g >> 4);
ct[i].b |= (ct[i].b >> 4);
}
for (i = 0; i < ncolors; i++) { // scale to 32 bits
g = ct[i].r;
ct[i].r |= ((g << 24) | (g << 16) | (g << 8));
g = ct[i].g;
ct[i].g |= ((g << 24) | (g << 16) | (g << 8));
g = ct[i].b;
ct[i].b |= ((g << 24) | (g << 16) | (g << 8));
}
}
else if (*colortable = (WORD *)calloc(ncolors, sizeof(WORD))) {
WORD *ct = *colortable;
while (ncheck--) {
r = (*rgb++ & 0xf0) << 4;
g = *rgb++ & 0xf0;
b = *rgb++ >> 4;
*(ct++) = r | g | b;
}
}
else {
errctab: *colortable = NULL;
*colors = 0xffff;
}
}
else *colors = 0xffff;
}
// pull out video mode information that was read in, if mode != NULL
if (mode) {
DisplayInfoHandle displayhandle;
struct DimensionInfo dimensioninfo;
UWORD maxdepth = MAXAMDEPTH;
// next 3 lines adapted from getdisplay() in modules/getdisplay.c
if (RowBytes(*wide) < RowBytes((*bmhd)->pageWidth))
*wide = (*bmhd)->pageWidth;
*high = max(*high, (*bmhd)->pageHeight);
// next 5 lines from maxdisplaydepth() in modules/getdisplay.c
if (((struct Library *)GfxBase)->lib_Version >= 37)
if (displayhandle = FindDisplayInfo(*mode))
if (GetDisplayInfoData(displayhandle, (UBYTE *)&dimensioninfo,
sizeof(struct DimensionInfo), DTAG_DIMS, NULL))
maxdepth = dimensioninfo.MaxDepth;
*deep = min(*deep, maxdepth); // from getdisplay() in modules/getdisplay.c
// Remainder of this if() block Adapted from getcamg() in modules/ilbmr.c
*mode = 0L;
if (sp = FindProp(iff, ID_ILBM, ID_CAMG)) {
*mode = (*(unsigned long *)sp->sp_Data);
// knock bad bits out of old-style 16-bit viewmode CAMGs
if ((!(*mode & MONITOR_ID_MASK)) ||
((*mode & EXTENDED_MODE) && (!(*mode & 0xffff0000))))
*mode &= (~(EXTENDED_MODE | SPRITES | GENLOCK_AUDIO
| GENLOCK_VIDEO | VP_HIDE));
// check for bogus CAMG like DPaintII brushes
if ((*mode & 0xffff0000) && (!(*mode & 0x00001000))) sp = NULL;
}
if (!sp) { // no CAMG or bad CAMG present - use computed modes
if (*wide >= 640) *mode = HIRES;
if (*high >= 400) *mode |= LACE;
if (*deep == 6) *mode |= HAM; // or EXTRA_HALFBRITE
}
}
#endif
return iff;
iffdone:
if (iff) freeIFFHandle(iff);
return NULL;
}
//===========================================================================
// FREEIFFHANDLE -- ref: loadilbmScreen(), loadilbmBitMap(), getilbminfo()
// Free the IFF Handle allocated by getilbminfo().
//===========================================================================
void freeIFFHandle(struct IFFHandle *iff)
{
CloseIFF(iff);
if (iff->iff_Stream) Close(iff->iff_Stream);
FreeIFF(iff);
}
//===========================================================================
// LOADBODY -- called by loadilbm()
// Setup to load an IFF ILBM body into a bitmap. Nonzero return means error.
// This function expects the parser to be stopped at the beginning of the
// BODY chunk of a file. Adapted from modules/ilbmr.c
//===========================================================================
int loadbody(struct IFFHandle *iff, struct BitMap *bitmap,BitMapHeader *bmhd)
{
BYTE *buffer;
ULONG bufsize;
LONG err = 0;
register struct ContextNode *cn = CurrentChunk(iff);
if (!cn) return 1;
if (cn->cn_Type != ID_ILBM || cn->cn_ID != ID_BODY) return 1;
if (bitmap && bmhd) {
bufsize = MaxPackedSize(RowBytes(bmhd->w)) << 4;
if (!(buffer = AllocMem(bufsize, 0L))) return 2;
err = loadbody2(iff, bitmap, NULL, bmhd, buffer, bufsize);
}
FreeMem(buffer, bufsize);
return err;
}
//===========================================================================
// LOADBODY2 -- called by loadbody()
// Load an IFF ILBM body into a bitmap. Nonzero return means error.
// From modules/ilbmr.c
//===========================================================================
#define MaxSrcPlanes (25)
int loadbody2(struct IFFHandle *iff, struct BitMap *bitmap,
BYTE *mask, BitMapHeader *bmhd, BYTE *buffer, ULONG bufsize)
{
register int iPlane, iRow, nEmpty;
register WORD nFilled;
WORD srcRowBytes = RowBytes(bmhd->w),
destRowBytes = bitmap->BytesPerRow,
destWidthBytes, // used for width check
compression = bmhd->compression;
LONG bufRowBytes = MaxPackedSize(srcRowBytes);
int nRows = bmhd->h;
struct ContextNode *cn = CurrentChunk(iff);
UBYTE srcPlaneCnt = bmhd->nPlanes;
BYTE *buf, *nullDest, *nullBuf, **pDest,
*planes[MaxSrcPlanes]; // array of ptrs to planes & mask
if (compression > cmpByteRun1) return 1;
if (((struct Library *)GfxBase)->lib_Version >= 39)
destWidthBytes = RowBytes(GetBitMapAttr(bitmap, BMA_WIDTH));
else
destWidthBytes = destRowBytes;
if (srcRowBytes > destWidthBytes || bufsize < (bufRowBytes<<1)
|| srcPlaneCnt > MaxSrcPlanes) return 1;
if (nRows > bitmap->Rows) nRows = bitmap->Rows;
// Initialize array "planes" with bitmap ptrs; NULL in empty slots.
for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
while (iPlane < MaxSrcPlanes) planes[iPlane++] = NULL;
// copy any mask plane ptr into corresponding "planes" slot.
if (bmhd->masking == mskHasMask)
planes[srcPlaneCnt++] = mask ? mask : NULL;
// Set up a sink for dummy destination of rows from unwanted planes
nullDest = buffer;
buffer += srcRowBytes;
bufsize -= srcRowBytes;
// Read the BODY contents into bitmap.
// De-interleave planes, decompress rows.
// MODIFIES: Last iteration modifies bufsize.
buf = buffer + bufsize; // buffer is currently empty
for (iRow = nRows; iRow > 0; iRow--) {
#ifdef TIMECHECK
if (!(iRow%(40/srcPlaneCnt))) check_for_switch(); // do it every few rows
#endif
for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++) {
pDest = &planes[iPlane];
if (!(*pDest)) { // establish sink for any unwanted plane
nullBuf = nullDest;
pDest = &nullBuf;
}
// read in at least enough bytes to uncompress next row
nEmpty = buf - buffer; // size of empty part of buffer
nFilled = bufsize - nEmpty; // this part has data
if (nFilled < bufRowBytes) {
CopyMem(buf, buffer, nFilled);
if (nEmpty > ChunkMoreBytes(cn)) { // not enough left to fill buffer
nEmpty = ChunkMoreBytes(cn);
bufsize = nFilled + nEmpty;
}
if (ReadChunkBytes(iff, &buffer[nFilled], nEmpty) < nEmpty) return 1;
buf = buffer;
nFilled = bufsize;
// nEmpty = 0; // dead assignment
}
// copy uncompressed row to destination plane
if (compression == cmpNone) {
if (nFilled < srcRowBytes) return 2;
CopyMem(buf, *pDest, srcRowBytes);
buf += srcRowBytes;
*pDest += destRowBytes;
}
else { // decompress row to destination plane
if (unpackrow(&buf, pDest, nFilled, srcRowBytes))
return 2;
else
*pDest += (destRowBytes - srcRowBytes);
}
}
}
return 0;
}
//===========================================================================
// UNPACKROW -- called by loadbody2()
// Given pointers to pointer variables, unpack one row, updating the source
// and destination pointers until it produces dstBytes bytes.
// From modules/unpacker.c
//===========================================================================
BOOL unpackrow(BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0)
{
register BYTE *source = *pSource;
register BYTE *dest = *pDest;
register WORD n;
register WORD srcBytes = srcBytes0, dstBytes = dstBytes0;
register BYTE c;
BOOL error = TRUE; // assume error until we make it through the loop
WORD minus128 = -128; // get the compiler to generate a CMP.W
while (dstBytes > 0) {
if (--srcBytes < 0) goto errorexit;
n = *source++;
if (n >= 0) {
++n;
if ((srcBytes -= n) < 0) goto errorexit;
if ((dstBytes -= n) < 0) goto errorexit;
do { *dest++ = *source++; } while (--n > 0);
}
else if (n != minus128) {
n = 1 - n;
if (--srcBytes < 0) goto errorexit;
if ((dstBytes -= n) < 0) goto errorexit;
c = *source++;
do { *dest++ = c; } while (--n > 0);
}
}
error = FALSE; // success!
errorexit:
*pSource = source; *pDest = dest;
return error;
}
#ifdef USE_GETBM // ignore getBitMap() if USE_GETBM not defined
//=========================================================================
// GETBITMAP
// Allocate a bitmap according to the dimensions provided, clear it if
// clear is nonzero, and return a pointer to the bitmap. NULL is returned
// if the bitmap couldn't be created.
// This function has nothing to do with modules/getbitmap.c in the RKM.
//=========================================================================
struct BitMap *getBitMap(int wide, int high, int deep, short clear)
{
register short i;
struct BitMap *bitmap;
if (!(bitmap = (struct BitMap *)
AllocMem(sizeof(struct BitMap), MEMF_PUBLIC|MEMF_CLEAR)))
goto bitmaperr;
InitBitMap(bitmap, deep, wide, high);
for (i = 0; i < deep; i++) {
if (!(bitmap->Planes[i] = (PLANEPTR)AllocRaster(wide, high)))
goto bitmaperr;
if (clear) BltClear(bitmap->Planes[i], RASSIZE(wide, high), 0);
}
return bitmap;
bitmaperr:
freeBitMap(bitmap);
return NULL;
}
#endif
#ifdef USE_FREEBM // ignore freeBitMap() if USE_FREEBM not defined
//==========================================================================
// FREEBITMAP
// Deallocate a bitmap structure, with all its bitplanes.
//==========================================================================
void freeBitMap(struct BitMap *bm)
{
short j;
if (bm) {
for (j = 0; j < bm->Depth; j++)
if (bm->Planes[j])
FreeRaster(bm->Planes[j], bm->BytesPerRow << 3, bm->Rows);
FreeMem(bm, sizeof(struct BitMap));
}
}
#endif